package com.ruoyi.learn.java.design.pattern.creator;

/**
 * 建造者模式 (Builder Pattern) 示例：构建一台电脑。
 */
public class BuilderPatternDemo {

    //region ========== 1. 产品 (Product) ==========

    /**
     * 产品类：电脑 (Computer)
     * 这是一个复杂对象，由多个部件组成。
     * 构造函数私有，只能通过 Builder 创建。
     */
    public static class Computer {
        private final String cpu;       // 必需
        private final String memory;    // 必需
        private final String storage;   // 必需
        private final String gpu;       // 可选
        private final String os;        // 可选
        private final boolean bluetooth; // 可选
        private final boolean wifi;     // 可选

        // 私有构造函数，只能由 Builder 构建
        private Computer(StandardComputerBuilder builder) {
            this.cpu = builder.cpu;
            this.memory = builder.memory;
            this.storage = builder.storage;
            this.gpu = builder.gpu;
            this.os = builder.os;
            this.bluetooth = builder.bluetooth;
            this.wifi = builder.wifi;
        }

        // 提供 getter 方法
        public String getCpu() { return cpu; }
        public String getMemory() { return memory; }
        public String getStorage() { return storage; }
        public String getGpu() { return gpu; }
        public String getOs() { return os; }
        public boolean hasBluetooth() { return bluetooth; }
        public boolean hasWifi() { return wifi; }

        @Override
        public String toString() {
            return "Computer{" +
                    "cpu='" + cpu + '\'' +
                    ", memory='" + memory + '\'' +
                    ", storage='" + storage + '\'' +
                    ", gpu='" + gpu + '\'' +
                    ", os='" + os + '\'' +
                    ", bluetooth=" + bluetooth +
                    ", wifi=" + wifi +
                    '}';
        }
    }

    //endregion

    //region ========== 2. 抽象建造者 (Builder) & 具体建造者 (ConcreteBuilder) ==========

    /**
     * 抽象建造者 (Builder) 接口。
     * 定义构建电脑各个部分的方法。
     * 注意：通常建造者模式会将 Builder 作为 Product 的内部静态类。
     */
    // (这里我们将 Builder 作为 Computer 的内部类更常见，但为了结构清晰，先定义接口)
    // 实际上，在 Java 中，Builder 通常是 Product 的一个静态内部类。

    // 为了展示标准结构，我们定义一个 Builder 接口
    public interface ComputerBuilder {
        ComputerBuilder setCpu(String cpu);
        ComputerBuilder setMemory(String memory);
        ComputerBuilder setStorage(String storage);
        ComputerBuilder setGpu(String gpu);
        ComputerBuilder setOs(String os);
        ComputerBuilder setBluetooth(boolean bluetooth);
        ComputerBuilder setWifi(boolean wifi);
        Computer build(); // 返回最终构建好的产品
    }

    /**
     * 具体建造者 (ConcreteBuilder) 实现。
     * 实现了构建电脑的步骤。
     * 在实际应用中，通常会将 Builder 直接作为 Product 的内部静态类。
     */
    public static class StandardComputerBuilder implements ComputerBuilder {
        private String cpu;
        private String memory;
        private String storage;
        private String gpu;
        private String os;
        private boolean bluetooth;
        private boolean wifi;

        @Override
        public ComputerBuilder setCpu(String cpu) {
            this.cpu = cpu;
            return this; // 支持链式调用
        }

        @Override
        public ComputerBuilder setMemory(String memory) {
            this.memory = memory;
            return this;
        }

        @Override
        public ComputerBuilder setStorage(String storage) {
            this.storage = storage;
            return this;
        }

        @Override
        public ComputerBuilder setGpu(String gpu) {
            this.gpu = gpu;
            return this;
        }

        @Override
        public ComputerBuilder setOs(String os) {
            this.os = os;
            return this;
        }

        @Override
        public ComputerBuilder setBluetooth(boolean bluetooth) {
            this.bluetooth = bluetooth;
            return this;
        }

        @Override
        public ComputerBuilder setWifi(boolean wifi) {
            this.wifi = wifi;
            return this;
        }

        @Override
        public Computer build() {
            // 可以在这里进行参数校验
            if (cpu == null || memory == null || storage == null) {
                throw new IllegalStateException("CPU, Memory, and Storage are required!");
            }
            return new Computer(this); // 将自身（Builder）传递给 Computer 的私有构造函数
        }
    }

    //endregion

    //region ========== 3. 指挥者 (Director) ==========

    /**
     * 指挥者 (Director)
     * 负责定义构建产品的步骤顺序。
     * 它不关心具体的产品类型，只依赖于 Builder 接口。
     */
    public static class ComputerDirector {
        private ComputerBuilder builder;

        public ComputerDirector(ComputerBuilder builder) {
            this.builder = builder;
        }

        // 定义一个构建游戏电脑的流程
        public Computer constructGamingComputer() {
            return builder
                    .setCpu("Intel i9")
                    .setMemory("32GB DDR5")
                    .setStorage("1TB NVMe SSD")
                    .setGpu("NVIDIA RTX 4090")
                    .setOs("Windows 11")
                    .setBluetooth(true)
                    .setWifi(true)
                    .build();
        }

        // 定义一个构建办公电脑的流程
        public Computer constructOfficeComputer() {
            return builder
                    .setCpu("Intel i5")
                    .setMemory("16GB DDR4")
                    .setStorage("512GB SSD")
                    .setOs("Ubuntu 22.04") // 办公可能用 Linux
                    .setWifi(true)
                    .setBluetooth(false) // 办公可能不需要蓝牙
                    .build();
        }

        // 可以设置不同的建造者
        public void setBuilder(ComputerBuilder builder) {
            this.builder = builder;
        }
    }

    //endregion

    //region ========== 4. 更常见的 Java 风格实现 (Builder 作为内部类) ==========

    /**
     * 这是 Java 中更常见的建造者模式写法：
     * 将 Builder 作为 Product 的一个静态内部类。
     * 这样可以更紧密地结合，并且可以直接访问外部类的私有成员（虽然这里用构造函数传参）。
     */
    public static class ModernComputer {
        private final String cpu;
        private final String memory;
        private final String storage;
        private final String gpu;
        private final String os;
        private final boolean bluetooth;
        private final boolean wifi;

        // 私有构造函数
        private ModernComputer(Builder builder) {
            this.cpu = builder.cpu;
            this.memory = builder.memory;
            this.storage = builder.storage;
            this.gpu = builder.gpu;
            this.os = builder.os;
            this.bluetooth = builder.bluetooth;
            this.wifi = builder.wifi;
        }

        // Builder 作为静态内部类
        public static class Builder {
            // 必需参数
            private final String cpu;
            private final String memory;
            private final String storage;

            // 可选参数 - 初始化为默认值
            private String gpu = null;
            private String os = null;
            private boolean bluetooth = false;
            private boolean wifi = false;

            // 构造函数只接收必需参数
            public Builder(String cpu, String memory, String storage) {
                this.cpu = cpu;
                this.memory = memory;
                this.storage = storage;
            }

            // 设置可选参数的方法，返回 Builder 自身以支持链式调用
            public Builder gpu(String gpu) {
                this.gpu = gpu;
                return this;
            }

            public Builder os(String os) {
                this.os = os;
                return this;
            }

            public Builder bluetooth(boolean bluetooth) {
                this.bluetooth = bluetooth;
                return this;
            }

            public Builder wifi(boolean wifi) {
                this.wifi = wifi;
                return this;
            }

            // build() 方法创建并返回最终的 Product
            public ModernComputer build() {
                if (cpu == null || memory == null || storage == null) {
                    throw new IllegalStateException("必需参数缺失");
                }
                return new ModernComputer(this);
            }
        }

        // Getter 方法
        public String getCpu() { return cpu; }
        public String getMemory() { return memory; }
        public String getStorage() { return storage; }
        public String getGpu() { return gpu; }
        public String getOs() { return os; }
        public boolean hasBluetooth() { return bluetooth; }
        public boolean hasWifi() { return wifi; }

        @Override
        public String toString() {
            return "ModernComputer{" +
                    "cpu='" + cpu + '\'' +
                    ", memory='" + memory + '\'' +
                    ", storage='" + storage + '\'' +
                    ", gpu='" + gpu + '\'' +
                    ", os='" + os + '\'' +
                    ", bluetooth=" + bluetooth +
                    ", wifi=" + wifi +
                    '}';
        }
    }

    //endregion

    //region ========== 5. 主函数 (Main) - 演示两种实现方式 ==========

    public static void main(String[] args) {
        System.out.println("=== 建造者模式演示 ===\n");

        // 演示方式一：使用独立的 Builder 和 Director
        System.out.println("1. 使用 Director 和 ConcreteBuilder:");
        ComputerBuilder builder = new StandardComputerBuilder();
        ComputerDirector director = new ComputerDirector(builder);

        // 构建游戏电脑
        Computer gamingPc = director.constructGamingComputer();
        System.out.println("游戏电脑: " + gamingPc);

        // 构建办公电脑
        Computer officePc = director.constructOfficeComputer();
        System.out.println("办公电脑: " + officePc);

        // 演示方式二：使用内部类 Builder (更常见)
        System.out.println("\n2. 使用内部类 Builder (链式调用):");
        ModernComputer gamingPc2 = new ModernComputer.Builder("AMD Ryzen 9", "64GB DDR5", "2TB NVMe SSD")
                .gpu("AMD Radeon RX 7900 XTX")
                .os("Windows 11 Pro")
                .bluetooth(true)
                .wifi(true)
                .build();

        ModernComputer officePc2 = new ModernComputer.Builder("Apple M2", "16GB", "512GB SSD")
                .os("macOS Ventura")
                .wifi(true)
                .build(); // 蓝牙默认为 false

        System.out.println("新型游戏电脑: " + gamingPc2);
        System.out.println("新型办公电脑: " + officePc2);
    }

    //endregion
}
